package connect5.ia;

import java.util.Vector;

import connect5.Grille;

public class ValideCoup {
	
	int totalEvaluation = 0;
	int nombreCoupValidation = 5;
	
	private boolean aGagner;
	private boolean aPerdu;
	
	private int maxValue = 1000000;
	private int minValue = -1000000; 
	private Byte WALL = 4;
	private boolean DEBUG_MODE_MODE_1 = false;
	private boolean DEBUG_MODE_MODE_2 = false;
	private Vector<Byte> vecteur1 = new Vector<Byte>();
	private Vector<Byte> vecteur2 = new Vector<Byte>();
	
	public int determineValeur(Grille grille, int x, int y, Byte couleurJoueur) {
		long currentTime = System.currentTimeMillis();
		
		DEBUG_LN("Is currently trying to determine valor of grid \n " + grille.toString() + " \n For value X: " + y + " Y: " + x + " for turn of " + ( (couleurJoueur == JoueurArtificiel.VALUE_B)? "B" : "N" ));
		int point = 0;
		aGagner = false;
		aPerdu = false;
		
		// Initalisation des variables
		totalEvaluation = 0;
		
		vecteur1.clear();
        vecteur2.clear();
		
		// horizontal gauche
        for (int l = 0; l < nombreCoupValidation && 0 <= x-l-1 ; l++) { 
        	vecteur1.add(grille.getData()[x-l-1][y]);     	
        }
        
        // horizontal droit
        for (int l = 0; l < nombreCoupValidation && grille.getData().length > ( x+l+1) ; l++) {
        	vecteur2.add(grille.getData()[x+l+1][y]);     	
        }
        
        DEBUG_LN("Evaluating horizontal line");
        point = ValideValeurCoup(vecteur1, vecteur2, couleurJoueur);
        
        DEBUG_LN_LEVEL_2("Getting out of horizontal line " + (System.currentTimeMillis()-currentTime) + " milliseconds");
        
        DEBUG_LN("Evaluating horizontal line gived " + point + " points");
        totalEvaluation += point;
        
        vecteur1.clear();
        vecteur2.clear();

        // vertical haut
        for (int l = 0; l < nombreCoupValidation && 0 <= y-l-1 ; l++) { 
        	vecteur1.add(grille.getData()[x][y-l-1]);     	
        }
        
        // vertical bas
        for (int l = 0; l < nombreCoupValidation && (y + l + 1) < grille.getData()[0].length ; l++) {
        	vecteur2.add(grille.getData()[x][y+l+1]);     	
        }
        
        DEBUG_LN("Evaluating vertical line");
        point = ValideValeurCoup(vecteur1, vecteur2, couleurJoueur);
        
        DEBUG_LN("Evaluating vertical line gived " + point + " points");
        totalEvaluation += point;
        DEBUG_LN_LEVEL_2("Getting out of vertical line " + (System.currentTimeMillis()-currentTime) + " milliseconds");
        
        vecteur1.clear();
        vecteur2.clear();
        
        // diagonal \\ haut
        for (int l = 0; l < nombreCoupValidation && (y - l - 1) >= 0 && (x - l - 1) >= 0 ; l++) { 
        	vecteur1.add(grille.getData()[x-l-1][y-l-1]);     	
        }
        
        // diagonal \\ bas
        for (int l = 0; l < nombreCoupValidation && (x + l + 1) < grille.getData().length && (y + l + 1) < grille.getData()[0].length ; l++) {
        	vecteur2.add(grille.getData()[x+l+1][y+l+1]);     	
        }
        
        DEBUG_LN("Evaluating diagonal \\ line");
        point = ValideValeurCoup(vecteur1, vecteur2, couleurJoueur);
        
        DEBUG_LN("Evaluating diagonal \\ line gived " + point + " points");
        totalEvaluation += point;
        
        DEBUG_LN_LEVEL_2("Getting out of diagonal \\ " + (System.currentTimeMillis()-currentTime) + " milliseconds");
        
        vecteur1.clear();
        vecteur2.clear();
        
        // diagonal // haut
        for (int l = 0; l < nombreCoupValidation && (x+l+1) < grille.getData().length && (y - l - 1) >= 0 ; l++) {
        	vecteur1.add(grille.getData()[x+l+1][y-l-1]);     	
        }
        
        // diagonal // bas
        for (int l = 0; l < nombreCoupValidation && (x - l - 1) >= 0 && (y + l + 1) < grille.getData()[0].length ; l++) { 
        	vecteur2.add(grille.getData()[x-l-1][y+l+1]);     	
        }
        
        DEBUG_LN("Evaluating diagonal / line");
        point = ValideValeurCoup(vecteur1, vecteur2, couleurJoueur);
        
        DEBUG_LN("Evaluating diagonal / line gived " + point + " points");
        totalEvaluation += point;
        
        DEBUG_LN("Returning value (totalEvaluation) : " + totalEvaluation);
        DEBUG_LN_LEVEL_2("Getting out of here took " + (System.currentTimeMillis()-currentTime) + " milliseconds");
        if((System.currentTimeMillis()-currentTime) > 20){
        	DEBUG_LN_LEVEL_2("Configuration \n " + grille.toString() + " \nFor value X: " + y + " Y: " + x +" took too much seconds");
        }
		return totalEvaluation;
	}
	
	private int ValideValeurCoup(Vector<Byte> vecteur1, Vector<Byte> vecteur2, Byte couleurJoueur){
		DEBUG("Data is : ");

		for(int i = vecteur1.size()-1; i >= 0; i--){
			if( vecteur1.get(i) == JoueurArtificiel.VALUE_B)
				DEBUG("B");
			else if( vecteur1.get(i) == JoueurArtificiel.VALUE_N)
				DEBUG("N");
			else
				DEBUG("0");
		}
		DEBUG("[center]");
		for(int i = 0; i < vecteur2.size(); i++){
			if( vecteur2.get(i) == JoueurArtificiel.VALUE_B)
				DEBUG("B");
			else if( vecteur2.get(i) == JoueurArtificiel.VALUE_N)
				DEBUG("N");
			else
				DEBUG("0");
		}
		DEBUG("\n");
		
		Byte pieceGauche;	
		Byte pieceDroite;
		
		int point = 0;
		
		if ((vecteur1.size() + vecteur2.size()) < 4){
			DEBUG_LN_LEVEL_2("Line was not long enough to value point");
			return point; // ligne trop petite pour valoir des points;
		}
		else{
			while(vecteur1.size() < nombreCoupValidation){
				vecteur1.add(WALL);
			}
			while(vecteur2.size() < nombreCoupValidation){
				vecteur2.add(WALL);
			}
			
			pieceGauche = vecteur1.elementAt(0);
			
			if(pieceGauche == WALL){
				DEBUG_LN("First element of vector1 is considered to be a wall");
				if(vecteur2.elementAt(0) == trouveCouleurEnnemie(couleurJoueur)){ //WWWWWBN_____
					point+= vecteur1Ennemie(vecteur2, vecteur1, couleurJoueur);
				}
				else if(vecteur2.elementAt(0) == couleurJoueur){ //WWWWWBB_____
					point+= vecteur1Joueur(vecteur2, vecteur1, couleurJoueur);
				}
				else{ //WWWWWB0______
					return 1;
				}
				
			}
			///**** Si on a _____0B_____  ****///
			else if(pieceGauche == JoueurArtificiel.VALUE_0){
				DEBUG_LN("First element of vector1 is considered to be a 0");
				if(vecteur2.elementAt(0) == trouveCouleurEnnemie(couleurJoueur)){ //____0BN_____
					point+= vecteur1Ennemie(vecteur2, vecteur1, couleurJoueur);
				}
				else if(vecteur2.elementAt(0) == couleurJoueur){ //____0BB_____
					//if(pointPossible(vecteur1, vecteur2, couleurJoueur)){
						point+= vecteur1Joueur(vecteur2, vecteur1, couleurJoueur);
					//}
				}
				else if(vecteur2.elementAt(0) == WALL){// _____0BWWWWWW
					return 1;
				}
				else{   // _____0B0_______
					//   ____00B00____ 
					if((vecteur2.elementAt(1) == JoueurArtificiel.VALUE_0 )&& (vecteur1.elementAt(1) == JoueurArtificiel.VALUE_0)){
						return 3;
					}
					//  ____W0B00____ OU ____00B0W____ 
					else if((vecteur2.elementAt(1) == JoueurArtificiel.VALUE_0 || vecteur2.elementAt(1) == WALL)&& (vecteur1.elementAt(1) == WALL || vecteur1.elementAt(1) == JoueurArtificiel.VALUE_0)){
						return 1;
					}
					//else if(pointPossible(vecteur1, vecteur2, couleurJoueur))
					//{
					else
						point+=vecteur1Joueur(vecteur1, vecteur2, couleurJoueur);
					//}
				}
			}
				
			///**** Si on a _____BBX_____ ****/// 
			else if(pieceGauche == couleurJoueur){
				DEBUG_LN("First element of vector1 is considered to be a your piece");
				if (vecteur2.elementAt(0) == trouveCouleurEnnemie(couleurJoueur)) // ____BBN_____
					point += vecteur1Ennemie(vecteur2, vecteur1, couleurJoueur);
				else{															  // ____BBB_____
					//if(pointPossible(vecteur1, vecteur2, couleurJoueur))
						point += vecteur1Joueur(vecteur1, vecteur2, couleurJoueur);
				}
			}	
			
			///**** Si on a _____NBX_____  ****///
			else{ // couleurEnnemie
				DEBUG_LN("First element of vector1 is considered to be a ennemie piece");
				point += vecteur1Ennemie(vecteur1, vecteur2, couleurJoueur);
			}
		}
		
		return point;
	}
	
	private int vecteur1Joueur(Vector<Byte> vecteur1, Vector<Byte> vecteur2, Byte couleurJoueur){
		DEBUG_LN("Entered vecteur1Joueur");
		int indexDroite = 0;
		int pointDroit = 0;
		int pointGauche = 0;
		
		while(indexDroite < 4 && vecteur2.elementAt(indexDroite) == couleurJoueur){
			indexDroite++;
		}
		
		if(vecteur1.elementAt(4-(indexDroite)) != couleurJoueur){
			DEBUG_LN("The found patern is at indexDroite : " + indexDroite);
			pointDroit = calculPointForIndex(vecteur1,indexDroite,couleurJoueur,false);
			 
			if(pointDroit == 0 && vecteur1.elementAt(4-(indexDroite)) != couleurJoueur){
				indexDroite++;
				pointDroit = calculPointForIndex(vecteur1,indexDroite,couleurJoueur,true);
			}
		}
		
		int indexGauche = 0;
		
		while(indexGauche < 4 && vecteur1.elementAt(indexGauche) == couleurJoueur){
			indexGauche++;
		}
		
		if(vecteur2.elementAt(4-(indexGauche)) != couleurJoueur){
			DEBUG_LN("The found patern is at indexGauche : " + indexGauche);
			pointGauche = calculPointForIndex(vecteur2,indexGauche,couleurJoueur,false);
			 
			if(indexGauche == 0 && vecteur2.elementAt(4-(indexGauche)) != couleurJoueur){
				indexGauche++;
				pointGauche = calculPointForIndex(vecteur2,indexGauche,couleurJoueur,true);
			}
		}

		return java.lang.Math.max(pointDroit, pointGauche);
	}
	
	private int calculPointForIndex(Vector<Byte> vecteur, int index, byte couleurJoueur, boolean secondeChance){
		int point = 0;
		int nombreB = 0;
		int nombreEspace = 0;
		boolean obstacleEncontrer = false;
		
		nombreB = index + 1;
		if(secondeChance){
			nombreB--;
			nombreEspace++;
		}
		if(vecteur1.elementAt(index) == JoueurArtificiel.VALUE_0){
			nombreEspace++;
		}
		for(int i = 0; i < 5-index-1; i++){
			if(vecteur2.elementAt(i) == JoueurArtificiel.VALUE_0)
			{
				nombreEspace ++;
			}
			else if (vecteur2.elementAt(i)==couleurJoueur){
				nombreB++;
			}
			else{
				obstacleEncontrer = true;
			}
		}
		if(nombreB > 0 && !obstacleEncontrer){
			DEBUG_LN("Points have been added for gettings points. nombreB : " + nombreB + " nombreEspace : " + nombreEspace);
			// Calcul tes point ici
			point = java.lang.Math.max( point, (int)java.lang.Math.pow(10, nombreB) + (int)java.lang.Math.pow(2, nombreEspace));
		}
		
		return point;
	}
	
	private int vecteur1Ennemie(Vector<Byte> vecteur1, Vector<Byte> vecteur2, Byte couleurJoueur){
		DEBUG_LN("Entered vecteur1Ennemie");
		int point = 0;
		
		Byte pieceGauche = trouveCouleurEnnemie(couleurJoueur);
		int compteurPieceGauche = 0;
		int compteurPieceDroite = 0;
		
		while(vecteur1.elementAt(compteurPieceGauche)==pieceGauche && compteurPieceGauche < 5){
			compteurPieceGauche++;
		}
		while(vecteur2.elementAt(compteurPieceDroite)==pieceGauche  && compteurPieceDroite < 5){
			compteurPieceDroite++;
		}
		
		if(compteurPieceDroite + compteurPieceGauche <= 4){
			DEBUG_LN("Points have been added for blocking opponent");
			point += (int)java.lang.Math.pow(12, compteurPieceDroite + compteurPieceGauche); // Donne point pour avoir bloquer compteurPieceDroite + compteurPieceGauche de noir
		}

		if(compteurPieceDroite == 0 && vecteur2.elementAt(4) == couleurJoueur){ //            && pointPossible(vecteur2, couleurJoueur)){
			// Valide si on fait des points
			int nombreB = 0;
			int nombreEspace = 0;
			int nombreEspaceAttente = 0;
			boolean obstacleEncontrer = false;
			for(int i = 0; i < 4; i++){
				if(vecteur2.elementAt(compteurPieceDroite)==couleurJoueur){
					nombreB++;
					nombreEspace += nombreEspaceAttente;
				}
				else if(vecteur2.elementAt(compteurPieceDroite)== JoueurArtificiel.VALUE_0)
					nombreEspaceAttente++;
				else
					obstacleEncontrer = true;
			}
			// Donne les point en fonction de 
			// nombreB et nombreEspace
			if(nombreB > 0 && !obstacleEncontrer){
				DEBUG_LN("Points have been added for getting point while blocking opponent. " + point + " have been already lined");
				point += (int)java.lang.Math.pow(10, nombreB) + (int)java.lang.Math.pow(2, nombreEspace);
			}
		}
		return point;
	}
	/*
	private boolean pointPossible(Vector<Byte> vecteur, Byte couleurJoueur){
		DEBUG_LN("Entered pointPossible with 1 vector");
		Byte ennemie = null;
		
		if(vecteur.elementAt(4) == couleurJoueur){ // || vecteur.elementAt(4) == WALL) J'ai enlever cette partie étant donné que si la case est un WALL a cet endroit, cela ne derange pas le pointage
			DEBUG_LN("You can't do points (by 1 vector) because ofyourself !");
			return false;
		}

		ennemie = trouveCouleurEnnemie(couleurJoueur);
		
		for(int i = 0; i < 4 ; i++){
			if(vecteur.elementAt(i) == ennemie || vecteur.elementAt(i) == WALL){
				DEBUG_LN("You can't do points (by 1 vector) because of a wall or a ennemie");
				return false; // il n'y a pas assez d'espace pour faire des points
			}
		}
		DEBUG_LN("You are able to do points");
		return true;
	}
	
	private boolean pointPossible(Vector<Byte> vecteur1, Vector<Byte> vecteur2, Byte couleurJoueur){
		DEBUG_LN("Entered pointPossible with 2 vector");
		Byte ennemie = trouveCouleurEnnemie(couleurJoueur);
		int compteur1 = 0;
		int compteur2 = 0;
		
		for(int i = 0; i < 5 ; i++){
			if(vecteur1.elementAt(i) == ennemie || vecteur1.elementAt(i) == WALL){
				break; // il n'y a pas assez d'espace pour faire des points
			}
			compteur1++;
		}
		for(int i = 0; i < 5 ; i++){
			if(vecteur2.elementAt(i) == ennemie || vecteur2.elementAt(i) == WALL){
				break; // il n'y a pas assez d'espace pour faire des points
			}
			compteur2++;
		}
		
		DEBUG_LN("Within pointPossible with 2 vector. compteur1 : " + compteur1 + " compteur2 : " + compteur2);
		int totalCompteur = compteur1 + compteur2;
		
		if(totalCompteur<4){
			DEBUG_LN("Considered to dont have enough place to scores points");
			return false;
		}
		*/
		/*
		 * Les deux do..while suivant peuvent sembler nebuleux. Leur utilite est la suivante :
		 * Cela permet de regarder, en decalant le centre au besoin (selon une regle) pour 
		 * voir si la nouvelle entree est valide. On deplace le centre vers un cote tant et aussi
		 * longtemps qu'il y a des B vers ce cote. On fait cette demache pour les deux cotes.
		 * Si une des deux entrees est valide, on considere donc que la configuration a des points 
		 * possibles.
		 * 
		 * Supposons l'entree suivante BBBB0[B]0BBB0 (le [] designe l'element central).
		 * Ici, il n'y a pas de B sur aucun des cotes, donc cette demarche permet de tester si
		 * BBBB0[B] est valide, puis ensuite [B]0BBB0.
		 * 
		 * Supposons l'entree suivante 00B0B[B]B0000. Il y a un B des deux cotes, donc on va
		 * tester la validite de B[B]B0000 puis 00B0B[B]B.
		 * 
		 * Supposons l'entree suivante 00BB0[B]B0BBB. Il y a un B sur un des cotes, donc on va
		 * tester la validite de [B]B0BBB et de 00BB0[B]B.
		 * 
		 * Le boolean secondeChance permet de traité les derniers possibilité ressemblant à
		 * BB00B[B]B00BB. Si on applique l'algorithme sans "secondeChance", cela va nous donner
		 * les vecteurs BB00B[B]B et B[B]B00BB, qui sont tous deux non valide. Or, la configuration
		 * donnée est valide (00B[B]B00), donc le parametre secondeChance permet de refaire un autre 
		 * essaie en bougeant une fois supplémentaire le "centre". Ce qui donne 0B[B]B00BB et 
		 * BB00B[B]B0 ce qui est valide !
		 *//*
		int indexDroite = 0;
		boolean secondeChance = false;
		DEBUG_LN("Start from moving window at left");
		do{
			if(vecteur2.elementAt(indexDroite) != couleurJoueur ){
				DEBUG_LN("At left from indexDroite : " + indexDroite + " there is : "+ vecteur2.elementAt(indexDroite) + " and element at 4-(indexDroite) is : " + vecteur1.elementAt(4-(indexDroite)) + " and compteur1+1 + indexDroite = " + (compteur1+1 + indexDroite));
				if(vecteur1.elementAt(4-(indexDroite)) != couleurJoueur && (compteur1+1 + indexDroite) >= 4){
					DEBUG_LN("Window identified at indexDroite : " + indexDroite);
					return true;
				}
				else{
					if(secondeChance){
						DEBUG_LN("Second chance lost.");
						break;
					}
					else if(vecteur2.elementAt(indexDroite) == JoueurArtificiel.VALUE_0){
						DEBUG_LN("Second chance taken.");
						secondeChance = true;
						indexDroite++;
						continue;
					}
				}
			}
			if(secondeChance){
				break;
			}
			indexDroite++;
		}while(indexDroite < 5 && (vecteur2.elementAt(indexDroite) == couleurJoueur || secondeChance));
		
		int indexGauche = 0;
		secondeChance = false;
		DEBUG_LN("Moving window at right");
		do{
			if(vecteur1.elementAt(indexGauche) != couleurJoueur){
				DEBUG_LN("At right from indexGauche : " + indexGauche + " there is : "+ vecteur1.elementAt(indexGauche) + " and element at 4-(indexGauche) is : " + vecteur2.elementAt(4-(indexGauche)) + " and compteur2+1 + indexGauche = " + (compteur2+1 + indexGauche));
				if(vecteur2.elementAt(4-(indexGauche)) != couleurJoueur && (compteur2 +1 +indexGauche) >= 4){
					DEBUG_LN("Window identified at indexGauche : " + indexGauche);
					return true;
				}
				else{
					if(secondeChance){
						DEBUG_LN("Second chance lost.");
						break;
					}
					else if (vecteur2.elementAt(indexDroite) == JoueurArtificiel.VALUE_0){
						DEBUG_LN("Second chance taken.");
						secondeChance = true;
						indexDroite++;
						continue;
					}
				}
			}
			if(secondeChance){
				break;
			}
			indexGauche++;
		}while(indexGauche < 5 && (vecteur1.elementAt(indexGauche) == couleurJoueur || secondeChance));

		return false;
		
	}
	*/
	private Byte trouveCouleurEnnemie(Byte couleurJoueur){
		if (couleurJoueur == JoueurArtificiel.VALUE_B)
			return JoueurArtificiel.VALUE_N;
		else
			return JoueurArtificiel.VALUE_B;
	}

	private void DEBUG_LN(String data){
		if(DEBUG_MODE_MODE_1){
			System.out.println(data);
		}
	}
	private void DEBUG(String data){
		if(DEBUG_MODE_MODE_1){
			System.out.print(data);
		}
	}
	
	private void DEBUG_LN_LEVEL_2(String data){
		if(DEBUG_MODE_MODE_2){
			System.out.println(data);
		}
	}
}
